package com.tg.appcommon.android;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicBlur;
import android.view.Gravity;
import android.widget.ImageView;

import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.bitmap.TransformationUtils;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.CustomViewTarget;
import com.bumptech.glide.request.transition.Transition;
import com.tange.base.toolkit.AppUtil;
import com.tg.appcommon.transform.GrayscaleTransformation;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * Bitmap位图工具类
 */
@SuppressWarnings("unused")
public class BitmapUtil {
    /**
     * Bitmap缩放
     *
     * @param bitmap 位图
     * @param scale  缩放比例
     * @return 新建的缩放后的Bitmap
     */
    public static Bitmap scaleBitmap(Bitmap bitmap, float scale) {
        Matrix matrix = new Matrix();
        matrix.postScale(scale, scale); //长和宽放大缩小的比例
        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
    }

    /**
     * 使用Drawable新建Bitmap
     */
    public static Bitmap createBitmapWithDrawable(Drawable drawable) {
        Bitmap.Config config = (drawable.getOpacity() != PixelFormat.OPAQUE) ? (Bitmap.Config.ARGB_8888) : (Bitmap.Config.RGB_565);
        Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), config);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
        drawable.draw(canvas);
        return bitmap;
    }

    /**
     * 将Bitmap图片保存为文件
     *
     * @param saveFile 文件路径
     * @param bitmap   位图
     * @param format   格式
     */
    public static void saveBitmapToFile(File saveFile, Bitmap bitmap, Bitmap.CompressFormat format) {
        saveBitmapToFile(saveFile, bitmap, format, 100);
    }

    /**
     * 将Bitmap图片保存为文件
     *
     * @param saveFile 文件路径
     * @param bitmap   位图
     * @param format   格式
     * @param quality  压缩质量 1-100
     */
    public static void saveBitmapToFile(File saveFile, Bitmap bitmap, Bitmap.CompressFormat format, int quality) {
        if (null == saveFile || null == bitmap) {
            return;
        }
        FileOutputStream outputStream = null;
        try {
            if (!saveFile.exists()) {
                if (!saveFile.getParentFile().exists()) {
                    //noinspection ResultOfMethodCallIgnored
                    saveFile.getParentFile().mkdir();
                }
                //noinspection ResultOfMethodCallIgnored
                saveFile.createNewFile();
            }
            outputStream = new FileOutputStream(saveFile);
            if (bitmap.compress(format, quality, outputStream)) {
                outputStream.flush();
            }
        } catch (Exception e) {
            //
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * Bitmap进行裁剪
     * （在保持长宽比的前提下，缩放图片，使得图片填满容器）
     *
     * @param recycled 目标结果bitmap，传null则新建一个
     * @param source   要裁剪的bitmap
     * @param width    长度
     * @param height   高度
     * @param gravity  裁剪时获取哪图片的部分（如中间、底部）
     */
    @SuppressLint("RtlHardcoded")
    public static Bitmap resizeBitmapAspectFill(@Nullable Bitmap recycled, Bitmap source, int width, int height, int gravity) {
        if (source == null) {
            return null;
        } else if (source.getWidth() == width && source.getHeight() == height) {
            return source;
        }
        // From ImageView/Bitmap.createScaledBitmap.
        final float scale;
        float dx = 0, dy = 0;
        Matrix m = new Matrix();
        if (source.getWidth() * height > width * source.getHeight()) {
            scale = (float) height / (float) source.getHeight();
            gravity = gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
            if (gravity == Gravity.LEFT) {
                dx = 0;
            } else if (gravity == Gravity.RIGHT) {
                dx = (width - source.getWidth() * scale);
            } else {
                dx = (width - source.getWidth() * scale) * 0.5f;
            }
        } else {
            scale = (float) width / (float) source.getWidth();
            gravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
            if (gravity == Gravity.TOP) {
                dy = 0;
            } else if (gravity == Gravity.BOTTOM) {
                dy = (height - source.getHeight() * scale);
            } else {
                dy = (height - source.getHeight() * scale) * 0.5f;
            }
        }

        m.setScale(scale, scale);
        m.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));
        final Bitmap result;
        if (recycled != null) {
            result = recycled;
        } else {
            result = Bitmap.createBitmap(width, height, getSafeConfig(source));
        }

        // We don't add or remove alpha, so keep the alpha setting of the Bitmap we were given.
        TransformationUtils.setAlpha(source, result);

        Canvas canvas = new Canvas(result);
        Paint paint = new Paint(Paint.DITHER_FLAG | Paint.FILTER_BITMAP_FLAG);
        canvas.drawBitmap(source, m, paint);
        return result;

    }

    /**
     * Bitmap进行裁剪
     * （在保持长宽比的前提下，缩放图片，使得图片在容器内完整显示出来）
     *
     * @param source  要裁剪的bitmap
     * @param width   长度
     * @param height  高度
     * @param gravity 裁剪时获取哪图片的部分（如中间、底部）
     */
    @SuppressLint("RtlHardcoded")
    public static Bitmap resizeBitmapAspectFit(@Nullable Bitmap recycled, Bitmap source, int width, int height, int gravity) {
        if (source == null) {
            return null;
        } else if (source.getWidth() == width && source.getHeight() == height) {
            return source;
        }

        final float scale;
        float dx = 0, dy = 0;
        Matrix m = new Matrix();
        if (source.getWidth() * height < width * source.getHeight()) {
            scale = (float) height / (float) source.getHeight();
            gravity = gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
            if (gravity == Gravity.LEFT) {
                dx = 0;
            } else if (gravity == Gravity.RIGHT) {
                dx = (width - source.getWidth() * scale);
            } else {
                dx = (width - source.getWidth() * scale) * 0.5f;
            }
        } else {
            scale = (float) width / (float) source.getWidth();
            gravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
            if (gravity == Gravity.TOP) {
                dy = 0;
            } else if (gravity == Gravity.BOTTOM) {
                dy = (height - source.getHeight() * scale);
            } else {
                dy = (height - source.getHeight() * scale) * 0.5f;
            }
        }

        m.setScale(scale, scale);
        m.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));
        final Bitmap result;
        if (recycled != null) {
            result = recycled;
        } else {
            result = Bitmap.createBitmap(width, height, getSafeConfig(source));
        }

        TransformationUtils.setAlpha(source, result);

        Canvas canvas = new Canvas(result);
        Paint paint = new Paint(Paint.DITHER_FLAG | Paint.FILTER_BITMAP_FLAG);
        canvas.drawBitmap(source, m, paint);
        return result;
    }

    private static Bitmap.Config getSafeConfig(Bitmap bitmap) {
        return bitmap.getConfig() != null ? bitmap.getConfig() : Bitmap.Config.ARGB_8888;
    }

    private static RenderScript sRenderScript;

    public static Bitmap transform(Bitmap toTransform, int outWidth, int outHeight) {
//        toTransform = BitmapUtil.scaleBitmap(toTransform, mScale);
        int bitmapWidth = toTransform.getWidth();
        int bitmapHeight = toTransform.getHeight();
        float widthRatio = (float) outWidth / bitmapWidth;
        float heightRatio = (float) outHeight / bitmapHeight;
        Matrix matrix = new Matrix();
        int radius = 20;
        float scale = 0.125f;
        matrix.postScale(scale, scale * heightRatio / widthRatio); //长和宽放大缩小的比例
        toTransform = Bitmap.createBitmap(toTransform, 0, 0, toTransform.getWidth(), toTransform.getHeight(), matrix, true);
        return BitmapUtil.blurBitmap(TGApplicationBase.getApplicationContext(), toTransform, radius);
    }

    /**
     * 高斯模糊模糊
     *
     * @param context Context
     * @param source  要变换的位图
     * @param radius  半径 0 - 25
     */
    public static Bitmap blurBitmap(Context context, Bitmap source, int radius) {
        //(1)
        RenderScript renderScript = sRenderScript;
        if (renderScript == null) {
            renderScript = RenderScript.create(context.getApplicationContext());
            sRenderScript = renderScript;
        }

        // Allocate memory for Renderscript to work with
        //(2)
        final Allocation input = Allocation.createFromBitmap(renderScript, source);
        final Allocation output = Allocation.createTyped(renderScript, input.getType());
        //(3)
        // Load up an instance of the specific script that we want to use.
        ScriptIntrinsicBlur scriptIntrinsicBlur = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript));
        //(4)
        scriptIntrinsicBlur.setInput(input);
        //(5)
        // Set the blur radius
        scriptIntrinsicBlur.setRadius(radius);
        //(6)
        // Start the ScriptIntrinisicBlur
        scriptIntrinsicBlur.forEach(output);
        //(7)
        // Copy the output to the blurred bitmap
        output.copyTo(source);
        return source;
    }

    public static Bitmap circleCropBitmap(@NonNull Bitmap source, int destWidth, int destHeight, final float ratio, int padding) {
        return circleCropBitmap(source, destWidth, destHeight, ratio, padding, 0, 0);
    }

    /**
     * 裁剪圆形图片
     *
     * @param source      原始图片
     * @param destWidth   目标图片宽
     * @param destHeight  目标图片高
     * @param ratio       比例（1.0f）
     * @param padding     边距(px)，
     * @param stroke      描边宽度(px)，无描边填0
     * @param strokeColor 描边颜色
     */
    public static Bitmap circleCropBitmap(@NonNull Bitmap source, int destWidth, int destHeight, final float ratio, int padding, int stroke, @ColorInt int strokeColor) {
        final int width = source.getWidth();
        final int height = source.getHeight();
        final int scaledWidth = (int) (destWidth * ratio);
        final float radius = destHeight * ratio / 2 - padding;
        final float scale = (width > height) ? ((float) scaledWidth / (float) height) : ((float) scaledWidth / (float) width);

        final float cx = (float) destWidth / 2;
        final float cy = (float) destHeight / 2;


        final Bitmap result = Bitmap.createBitmap(destWidth, destHeight, Bitmap.Config.ARGB_8888);
        final Canvas canvas = new Canvas(result);
        canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));

        int saveCount = canvas.save();

        // 圆形图片
        final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setAntiAlias(true);
        canvas.drawCircle(cx, cy, radius, paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        final Matrix matrix = new Matrix();
        matrix.setScale(scale, scale);
        canvas.concat(matrix);
        canvas.drawBitmap(source, 0, 0, paint);
        paint.setXfermode(null);

        canvas.restoreToCount(saveCount);

        if (stroke > 0) {
            // 画描边
            Paint borderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            borderPaint.setStrokeWidth(stroke);
            borderPaint.setColor(strokeColor);
            borderPaint.setStyle(Paint.Style.STROKE);
            canvas.drawCircle(cx, cx, radius + stroke * 0.5f, borderPaint);
        }

        return result;
    }

    /**
     * 圆角边框图片
     */
    public static Bitmap cornersCropBitmap(BitmapPool pool, Bitmap source, float radius, int border,int borderColor) {
        if (source == null) {
            return null;
        }
        Bitmap result = pool.get(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
        if (result == null) {
            result = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
        }

        Canvas canvas = new Canvas(result);
        Paint paint = new Paint();
        paint.setShader(new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
        paint.setAntiAlias(true);
        RectF rectF = new RectF(border, border, source.getWidth() - border, source.getHeight() - border);
        canvas.drawRoundRect(rectF, radius, radius, paint);
        if (border > 0) {
            float padding = border / 2.0f;
            RectF borderRectF = new RectF(padding, padding, source.getWidth() - padding, source.getHeight() - padding);
            Paint borderPaint = new Paint();
            borderPaint.setDither(true);
            borderPaint.setAntiAlias(true);
            borderPaint.setStyle(Paint.Style.STROKE);
            borderPaint.setStrokeWidth(border);
            borderPaint.setColor(borderColor);
            canvas.drawRoundRect(borderRectF, radius, radius, borderPaint);
        }
        return result;
    }


    @SuppressLint("CheckResult")
    public static void setGrayViewBg(Context context, final ImageView imageView, int resId){
        if (AppUtil.isActivityFinishingOrDestroyed(context)) {
            return;
        }
        RequestOptions requestOptions = new RequestOptions().dontAnimate();
        GrayscaleTransformation transformation = new GrayscaleTransformation();
        RequestOptions other = RequestOptions.bitmapTransform(transformation);
        requestOptions.apply(other);
        Glide.with(context).load(resId).apply(requestOptions).into(new CustomViewTarget<ImageView, Drawable>(imageView) {
            @Override
            public void onLoadFailed(@Nullable Drawable errorDrawable) {

            }

            @Override
            public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
                imageView.setImageDrawable(resource);
            }
            @Override
            protected void onResourceCleared(@Nullable Drawable placeholder) {

            }

        });
    }
}
